﻿using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace JSLCloud.Utilities.Zip
{
    /// <summary>
    /// 压缩帮助类
    /// </summary>
    public static class ZipHelper
    {
        /// <summary>
        /// Zip文件压缩
        /// ZipOutputStream：相当于一个压缩包；
        /// ZipEntry：相当于压缩包里的一个文件；
        /// 以上两个类是SharpZipLib的主类。
        /// </summary>
        /// <param name="sourceFileLists"></param>
        /// <param name="descFile">压缩文件保存的目录</param>
        /// <param name="compression">压缩级别</param>
        public static void ZipCompress(List<string> sourceFileLists, string descFile, int compression = 3)
        {
            if (compression < 0 || compression > 9)
            {
                throw new ArgumentException("错误的压缩级别");
            }
            if (!Directory.Exists(new FileInfo(descFile).Directory.ToString()))
            {
                throw new ArgumentException("保存目录不存在");
            }
            foreach (string c in sourceFileLists)
            {
                if (!File.Exists(c))
                {
                    throw new ArgumentException(string.Format("文件{0} 不存在！", c));
                }
            }
            Crc32 crc32 = new Crc32();
            using (ZipOutputStream stream = new ZipOutputStream(File.Create(descFile)))
            {
                stream.SetLevel(compression);
                ZipEntry entry;
                for (int i = 0; i < sourceFileLists.Count; i++)
                {
                    entry = new ZipEntry(Path.GetFileName(sourceFileLists[i]))
                    {
                        DateTime = DateTime.Now
                    };
                    using (FileStream fs = File.OpenRead(sourceFileLists[i]))
                    {
                        byte[] buffer = new byte[fs.Length];
                        fs.Read(buffer, 0, buffer.Length);
                        entry.Size = fs.Length;
                        crc32.Reset();
                        crc32.Update(buffer);
                        entry.Crc = crc32.Value;
                        stream.PutNextEntry(entry);
                        stream.Write(buffer, 0, buffer.Length);
                    }
                    stream.CloseEntry();
                }

            }
        }

        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="sourceFilePath"></param>
        /// <param name="path"></param>
        public static void ZipDeCompress(string sourceFilePath,string path)
        {
            if (!File.Exists(sourceFilePath))
            {
                throw new Exception("file not found");
            }
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(sourceFilePath)))
            {
                ZipEntry currEntity;
                while((currEntity = zipStream.GetNextEntry()) != null)
                {
                    if (currEntity.IsDirectory)
                    {
                        if (!Directory.Exists($"{path}\\{currEntity.Name}"))
                        {
                            Directory.CreateDirectory($"{path}\\{currEntity.Name}");
                        }
                        continue;
                    }
                    else
                    {

                        var dir = "";
                        if(currEntity.Name.IndexOf("/") >= 0)
                        {
                            dir = $"{path}\\{currEntity.Name.Substring(0, currEntity.Name.IndexOf("/"))}";
                        }
                        else if (currEntity.Name.IndexOf("\\") >= 0)
                        {
                            dir = $"{path}\\{currEntity.Name.Substring(0, currEntity.Name.IndexOf("\\"))}";
                        }
                        if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        using (FileStream fs = File.Create($"{path}\\{currEntity.Name}"))
                        {
                            int size = 2048;
                            byte[] data = new byte[2048];
                            while (true)
                            {
                                size = zipStream.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    fs.Write(data, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                    
                }
            };
        }
    }
}
